#include "xbuffer.h"
#include "xtypes.h"
#include "xmemory.h"
#include <stdlib.h>
#include <string.h>


CxRingBuffer::CxRingBuffer()
{
	_Init();
	_Alloc( DEFAULT_BUFFER_SIZE );
}

CxRingBuffer::CxRingBuffer( int_t _Size )
{
	_Init();
	_Alloc( _Size );
}

CxRingBuffer::CxRingBuffer( const CxRingBuffer& _Ref )
{
	_Init();
	_Copy(_Ref);
}

CxRingBuffer::CxRingBuffer( const wildptr_t _DataPtr, int_t _Size )
{
	_Init();
	_Alloc( _Size );
	insert_back( _DataPtr, _Size );
}

CxRingBuffer& CxRingBuffer::operator=( const CxRingBuffer& _R )
{
	_Copy(_R);
	return *this;
}

CxRingBuffer::~CxRingBuffer()
{
	_Tidy();
}


int_t CxRingBuffer::capacity() const
{
	return m_PhySize;
}

int_t CxRingBuffer::size() const
{
	return m_DataSize;
}


xResult CxRingBuffer::resize( int_t _Size )
{
	if(_Size<0 || _Size>m_PhySize)
		return XR_FAIL;

	m_DataSize = _Size;
	return XR_OK;
}

xResult CxRingBuffer::insert_back( const wildptr_t _DataPtr, int_t _Size )
{
	if(_Size<=0)
		return XR_FAIL;

	const memptr_t pDataPtr = (memptr_t)_DataPtr;

	if( _Size + m_DataSize <= m_PhySize )
	{
		int_t nAppendPos = (m_nHead+m_DataSize)%m_PhySize;
		if( _Size <= m_PhySize-nAppendPos )
		{			
			memcpy( m_PhyPtr+nAppendPos, pDataPtr, _Size );
			m_DataSize+=_Size;			
		}
		else
		{
			const int_t nBlockSize1 = m_PhySize-nAppendPos;
			const int_t nBlockSize2 = _Size - nBlockSize1;			
			memcpy( m_PhyPtr+nAppendPos, pDataPtr, nBlockSize1 );
			memcpy( m_PhyPtr+0, pDataPtr+nBlockSize1, nBlockSize2 );
			m_DataSize+=_Size;			
		}
		return XR_OK;
	}
	else
	{
		return XR_FAIL;
	}
}


xResult CxRingBuffer::cut_front( wildptr_t _DataPtr, int_t _Size )
{
	xResult nRet = this->copy_front( _DataPtr, _Size );
	if( XR_SUCCESS(nRet) )
	{
		this->drop_front( _Size );
	}

	return nRet;
}


bool_t CxRingBuffer::empty() const
{
	if(m_PhySize<=0 || m_DataSize<=0)
		return TRUE;
	else
		return FALSE;
}
xResult CxRingBuffer::clear()
{
	drop_back(m_DataSize);
	m_nHead = 0;

	return XR_OK;
}


xResult CxRingBuffer::resize_capacity( int_t _NewSize )
{
	if(_NewSize < m_DataSize)
		return XR_FAIL;

	if( _NewSize == m_PhySize )
		return XR_OK;

	int_t nBlockSize = m_DataSize;
	CxStaticBuffer tmp( nBlockSize );
	copy_front(tmp.data(), nBlockSize);

	_Tidy();
	_Alloc(_NewSize);
	insert_back(tmp.data(), nBlockSize);

	return XR_OK;
}

void CxRingBuffer::_Init()
{
	m_PhyPtr = NULL;
	m_PhySize = 0;
	m_nHead = 0;
	m_DataSize = 0;
}

void CxRingBuffer::_Alloc( int_t _Size )
{
	if( _Size<=0 )
		return;

	_Tidy();

	m_PhyPtr = (memptr_t)xMemoryAlloc(_Size);
	if(m_PhyPtr!=NULL)
	{
		m_PhySize = _Size;
		m_DataSize = 0;
		m_nHead = 0;
	}
	else
	{
		m_PhyPtr = NULL;
		m_PhySize = 0;
		m_DataSize = 0;
		m_nHead = 0;
	}
}

void CxRingBuffer::_Tidy()
{
	if(m_PhyPtr!=NULL)
	{
		xMemoryFree(m_PhyPtr);
		m_PhyPtr = NULL;
		m_PhySize = 0;
		m_DataSize = 0;
		m_nHead = 0;
	}
}

void CxRingBuffer::_Copy(const CxRingBuffer& _Ref)
{
	_Tidy();
	_Alloc( _Ref.m_PhySize);

	if(m_PhyPtr!=NULL)
	{
		m_DataSize = _Ref.m_DataSize;
		m_nHead = _Ref.m_nHead;
		memcpy(m_PhyPtr, _Ref.m_PhyPtr, m_PhySize);
	}

}

xResult CxRingBuffer::drop_front( int_t _Size )
{
	if(_Size<=0)
		return XR_FAIL;

	if( _Size<= m_DataSize )
	{
		if(_Size <= m_PhySize-m_nHead)
		{
			m_DataSize -= _Size;
			m_nHead += _Size;
		}
		else
		{
			const int_t nBlockSize1 = m_PhySize-m_nHead;
			const int_t nBlockSize2 = _Size - nBlockSize1;
			m_DataSize-=_Size;
			m_nHead = nBlockSize2;
		}
		return XR_OK;
	}
	else
	{
		return XR_FAIL;
	}

}

xResult CxRingBuffer::copy_front( wildptr_t _DataPtr, int_t _Size ) const
{
	if(_Size<=0)
		return XR_FAIL;

	memptr_t pDataPtr = (memptr_t)_DataPtr;
	int_t nTargetPos = m_nHead;

	if( _Size<= m_DataSize )
	{
		if(_Size <= m_PhySize-nTargetPos)
		{
			memcpy( pDataPtr, m_PhyPtr + nTargetPos, _Size );			
		}
		else
		{
			const int_t nBlockSize1 = m_PhySize-nTargetPos;
			const int_t nBlockSize2 = _Size - nBlockSize1;			
			memcpy( pDataPtr, m_PhyPtr+nTargetPos, nBlockSize1 );
			memcpy( pDataPtr+nBlockSize1, m_PhyPtr, nBlockSize2 );

		}
		return XR_OK;
	}
	else
	{
		return XR_FAIL;
	}

}


xResult CxRingBuffer::insert_front( const wildptr_t _DataPtr, int_t _Size )
{
	if(_Size<=0)
		return XR_FAIL;

	const memptr_t pDataPtr = (memptr_t)_DataPtr;

	if( _Size + m_DataSize <= m_PhySize )
	{

		int_t nAppendPos = (m_nHead - _Size + m_PhySize) % m_PhySize;

		if( _Size <= m_PhySize-nAppendPos )
		{			
			memcpy( m_PhyPtr+nAppendPos, pDataPtr, _Size );
			m_DataSize+=_Size;			
		}
		else
		{
			const int_t nBlockSize1 = m_PhySize-nAppendPos;
			const int_t nBlockSize2 = _Size - nBlockSize1;			
			memcpy( m_PhyPtr+nAppendPos, pDataPtr, nBlockSize1 );
			memcpy( m_PhyPtr+0, pDataPtr+nBlockSize1, nBlockSize2 );
			m_DataSize+=_Size;
		}

		m_nHead = nAppendPos;
		return XR_OK;
	}
	else
	{
		return XR_FAIL;
	}
}


xResult CxRingBuffer::copy_back( wildptr_t _DataPtr, int_t _Size ) const
{
	if(_Size<=0)
		return XR_FAIL;

	memptr_t pDataPtr = (memptr_t)_DataPtr;
	int_t nTargetPos = (m_nHead + m_DataSize - _Size + m_PhySize) % m_PhySize;

	if( _Size<= m_DataSize )
	{
		if(_Size <= m_PhySize-nTargetPos)
		{
			memcpy( pDataPtr, m_PhyPtr + nTargetPos, _Size );			
		}
		else
		{
			const int_t nBlockSize1 = m_PhySize-nTargetPos;
			const int_t nBlockSize2 = _Size - nBlockSize1;			
			memcpy( pDataPtr, m_PhyPtr+nTargetPos, nBlockSize1 );
			memcpy( pDataPtr+nBlockSize1, m_PhyPtr, nBlockSize2 );

		}
		return XR_OK;
	}
	else
	{
		return XR_FAIL;
	}
}


xResult CxRingBuffer::drop_back( int_t _Size )
{
	if(_Size<=0)
		return XR_FAIL;

	int_t nTargetPos = (m_nHead + m_DataSize - _Size + m_PhySize) % m_PhySize;

	if( _Size<= m_DataSize )
	{
		m_DataSize -= _Size;
		return XR_OK;
	}
	else
	{
		return XR_FAIL;
	}
}


xResult CxRingBuffer::cut_back( wildptr_t _DataPtr, int_t _Size )
{
	xResult nRet = this->copy_back( _DataPtr, _Size );
	if( XR_SUCCESS(nRet) )
	{
		this->drop_back( _Size );
	}
	return nRet;
}


memptr_t CxRingBuffer::data()
{
	_Serialize();	
	return m_PhyPtr;
}

xResult CxRingBuffer::insert( int_t _BeginPos, const wildptr_t _DataPtr, int_t _Size )
{
	if(_BeginPos<0 || _BeginPos>m_DataSize)
		return XR_FAIL;
	if(_Size<0)
		return XR_FAIL;

	CxStaticBuffer tmp(m_DataSize-_BeginPos);
	cut_back(tmp.data(), tmp.size());
	insert_back(_DataPtr, _Size);
	insert_back(tmp.data(), tmp.size());

	return XR_OK;
}

xResult CxRingBuffer::copy( int_t _BeginPos, wildptr_t _DataPtr, int_t _Size ) const
{
	if(_BeginPos<0 || _BeginPos>m_DataSize)
		return XR_FAIL;
	if(_Size<0 || _BeginPos+_Size>m_DataSize)
		return XR_FAIL;

	CxStaticBuffer tmp(m_DataSize - _BeginPos);
	copy_back(tmp.data(), tmp.size());
	memcpy(_DataPtr, tmp.data(), _Size);
	return XR_OK;
}

xResult CxRingBuffer::drop( int_t _BeginPos, int_t _Size )
{
	if(_BeginPos<0 || _BeginPos>m_DataSize)
		return XR_FAIL;
	if(_Size<0 || _BeginPos+_Size>m_DataSize)
		return XR_FAIL;

	CxStaticBuffer tmp(m_DataSize - _BeginPos);
	cut_back(tmp.data(), tmp.size());
	insert_back(tmp.data()+_BeginPos, tmp.size()-_BeginPos);

	return XR_OK;
}

xResult CxRingBuffer::cut( int_t _BeginPos, wildptr_t _DataPtr, int_t _Size )
{
	xResult nRet = this->copy( _BeginPos, _DataPtr, _Size );
	if( XR_SUCCESS(nRet) )
	{
		this->drop( _BeginPos, _Size );
	}
	return nRet;
}

int_t CxRingBuffer::length()
{
	return m_DataSize;
}

memptr_t CxRingBuffer::fragment_ptr()
{
	return m_PhyPtr + m_nHead;
}

int_t CxRingBuffer::fragment_len()
{
	return m_PhySize - m_nHead;
}

void CxRingBuffer::_Serialize()
{
	CxStaticBuffer tmp(m_DataSize);
	copy_back(tmp.data(), tmp.size());
	memcpy(m_PhyPtr, tmp.data(), m_DataSize);
	m_nHead = 0;
}

/*************************************************************************************************************
************************************************************************************************************
************************************************************************************************************
************************************************************************************************************
************************************************************************************************************
************************************************************************************************************
*************************************************************************************************************/






memptr_t CxDynamicBuffer::data() const
{
	return m_PhyPtr;
}

int_t CxDynamicBuffer::size() const
{
	return m_DataSize;
}

xResult CxDynamicBuffer::resize( int_t _Size )
{
	if(_Size<0 || _Size>m_PhySize)
		return XR_FAIL;

	m_DataSize = _Size;
	return XR_OK;
}

int_t CxDynamicBuffer::capacity() const
{
	return m_PhySize;
}

xResult CxDynamicBuffer::resize_capacity( int_t _NewSize )
{
	if(_NewSize < m_DataSize)
		return XR_FAIL;

	if( _NewSize == m_PhySize )
		return XR_OK;

	int_t nBlockSize = m_DataSize;

	memptr_t _Ptr = (memptr_t)xMemoryAlloc(_NewSize);
	if(_Ptr==NULL)
		return XR_FAIL;

	copy_front(_Ptr, nBlockSize);
	xMemoryFree(m_PhyPtr);
	m_PhyPtr = _Ptr;
	m_PhySize = _NewSize;
	m_DataSize = nBlockSize;

	//	CxStaticBuffer tmp( nBlockSize );
	// 	copy_front(tmp.data(), nBlockSize);
	// 
	// 	_Tidy();
	// 	_Alloc(_NewSize);
	// 	insert_back(tmp.data(), nBlockSize);

	return XR_OK;
}

bool_t CxDynamicBuffer::empty() const
{
	if(m_PhySize<=0 || m_DataSize<=0)
		return TRUE;
	else
		return FALSE;
}

xResult CxDynamicBuffer::clear()
{
	drop_back(m_DataSize);
	return XR_OK;
}

CxDynamicBuffer::CxDynamicBuffer()
{
	_Init();
	_Alloc( DEFAULT_BUFFER_SIZE );
}

CxDynamicBuffer::CxDynamicBuffer( int_t _Size )
{
	_Init();
	_Alloc( _Size );
}

CxDynamicBuffer::CxDynamicBuffer( const CxDynamicBuffer& _Ref )
{
	_Init();
	_Copy(_Ref);
}

CxDynamicBuffer::CxDynamicBuffer( const wildptr_t _DataPtr, int_t _Size )
{
	_Init();
	_Alloc( _Size );
	insert_back( _DataPtr, _Size );
}
CxDynamicBuffer& CxDynamicBuffer::operator=( const CxDynamicBuffer& _R )
{
	_Copy(_R);
	return *this;
}

CxDynamicBuffer::~CxDynamicBuffer()
{
	_Tidy();
}

void CxDynamicBuffer::_Init()
{
	m_PhyPtr = NULL;
	m_PhySize = 0;
	m_DataSize = 0;
}

void CxDynamicBuffer::_Alloc( int_t _Size )
{
	if( _Size<=0 )
		return;

	_Tidy();

	m_PhyPtr = (memptr_t)xMemoryAlloc(_Size);
	if(m_PhyPtr!=NULL)
	{
		m_PhySize = _Size;
		m_DataSize = 0;
	}
	else
	{
		m_PhyPtr = NULL;
		m_PhySize = 0;
		m_DataSize = 0;
	}
}

void CxDynamicBuffer::_Tidy()
{
	if(m_PhyPtr!=NULL)
	{
		xMemoryFree(m_PhyPtr);
		m_PhyPtr = NULL;
		m_PhySize = 0;
		m_DataSize = 0;
	}
}

void CxDynamicBuffer::_Copy( const CxDynamicBuffer& _Ref )
{
	_Tidy();
	_Alloc( _Ref.m_PhySize);

	if(m_PhyPtr!=NULL)
	{
		m_DataSize = _Ref.m_DataSize;
		memcpy(m_PhyPtr, _Ref.m_PhyPtr, m_PhySize);
	}
}

xResult CxDynamicBuffer::insert_front( const wildptr_t _DataPtr, int_t _Size )
{
	return this->insert( 0, _DataPtr, _Size );
}

xResult CxDynamicBuffer::drop_front( int_t _Size )
{
	return this->drop(0, _Size );
}

xResult CxDynamicBuffer::copy_front( wildptr_t _DataPtr, int_t _Size ) const
{
	return this->copy( 0, _DataPtr, _Size );
}

xResult CxDynamicBuffer::cut_front( wildptr_t _DataPtr, int_t _Size )
{
	return this->cut( 0, _DataPtr, _Size );
}

xResult CxDynamicBuffer::insert_back( const wildptr_t _DataPtr, int_t _Size )
{
	return this->insert( m_DataSize, _DataPtr, _Size );
}

xResult CxDynamicBuffer::drop_back( int_t _Size )
{
	return this->drop( m_DataSize - _Size, _Size );
}

xResult CxDynamicBuffer::copy_back( wildptr_t _DataPtr, int_t _Size ) const
{
	return this->copy( m_DataSize - _Size, _DataPtr, _Size );
}

xResult CxDynamicBuffer::cut_back( wildptr_t _DataPtr, int_t _Size )
{
	return this->cut( m_DataSize - _Size, _DataPtr, _Size );
}

xResult CxDynamicBuffer::copy( int_t _BeginPos, wildptr_t _DataPtr, int_t _Size ) const
{
	if( _Size<=0 )
		return XR_FAIL;
	if(_BeginPos<0 || _BeginPos>m_DataSize)
		return XR_FAIL;
	if( _BeginPos+_Size > m_DataSize)
		return XR_FAIL;

	memcpy( _DataPtr, m_PhyPtr, _Size);
	return XR_OK;
}

xResult CxDynamicBuffer::drop( int_t _BeginPos, int_t _Size )
{
	if( _Size<=0 )
		return XR_FAIL;
	if( _BeginPos<0 || _BeginPos>m_DataSize)
		return XR_FAIL;
	if( _BeginPos+_Size > m_DataSize)
		return XR_FAIL;

	int_t nRestLen = m_DataSize-(_BeginPos+_Size);
	if(  nRestLen>0 )
	{
		memcpy( m_PhyPtr+_BeginPos, m_PhyPtr+_BeginPos+_Size, nRestLen );
	}
	m_DataSize -= _Size;
	return XR_OK;
}

xResult CxDynamicBuffer::insert( int_t _BeginPos, const wildptr_t _DataPtr, int_t _Size )
{
	if( _Size<=0 )
		return XR_FAIL;
	if( _BeginPos<0 || _BeginPos>m_DataSize)
		return XR_FAIL;

	if( m_DataSize+_Size>m_PhySize)
		return XR_FAIL;

	int_t nLastPartLen = m_DataSize-_BeginPos;
	if( nLastPartLen>0)
	{
		memcpy( m_PhyPtr+_BeginPos+_Size, m_PhyPtr+_BeginPos, nLastPartLen );
	}		
	memcpy( m_PhyPtr+_BeginPos, _DataPtr, _Size );
	m_DataSize += _Size;
	return XR_OK;
}

xResult CxDynamicBuffer::cut( int_t _BeginPos, wildptr_t _DataPtr, int_t _Size )
{
	xResult nRet = this->copy( _BeginPos, _DataPtr, _Size );
	if( XR_SUCCESS(nRet) )
	{
		this->drop( _BeginPos, _Size );
	}
	return nRet;
}


/*************************************************************************************************************
************************************************************************************************************
************************************************************************************************************
************************************************************************************************************
************************************************************************************************************
************************************************************************************************************
*************************************************************************************************************/










memptr_t CxStaticBuffer::data() const
{
	return m_PhyPtr;
}

int_t CxStaticBuffer::size() const
{
	return m_PhySize;
}

int_t CxStaticBuffer::capacity() const
{
	return m_PhySize;
}

xResult CxStaticBuffer::resize_capacity( int_t _NewSize )
{
	memptr_t _Ptr = (memptr_t)xMemoryAlloc(_NewSize);
	if(_Ptr==NULL)
		return XR_FAIL;

	xMemoryFree(m_PhyPtr);
	m_PhyPtr = _Ptr;
	m_PhySize = _NewSize;
	return XR_OK;
}

CxStaticBuffer::CxStaticBuffer()
{
	_Init();
	_Alloc(DEFAULT_BUFFER_SIZE);
}

CxStaticBuffer::CxStaticBuffer( int_t _Size )
{
	_Init();
	_Alloc(_Size);
}

CxStaticBuffer::CxStaticBuffer( const CxStaticBuffer& _Ref )
{
	_Init();
	_Copy(_Ref);
}

CxStaticBuffer::CxStaticBuffer( const wildptr_t _DataPtr, int_t _Size )
{
	_Init();
	_Alloc(_Size);
	if(m_PhyPtr!=NULL)
	{
		memcpy(m_PhyPtr, _DataPtr, _Size);
	}
}
CxStaticBuffer& CxStaticBuffer::operator=( const CxStaticBuffer& _R )
{
	_Copy(_R);
	return *this;
}

CxStaticBuffer::~CxStaticBuffer()
{
	_Tidy();
}

void CxStaticBuffer::_Init()
{
	m_PhyPtr = NULL;
	m_PhySize = 0;
}

void CxStaticBuffer::_Alloc( int_t _Size )
{
	if( _Size<=0 )
		return;

	_Tidy();

	m_PhyPtr = (memptr_t)xMemoryAlloc(_Size);
	if(m_PhyPtr!=NULL)
	{
		m_PhySize = _Size;
	}
	else
	{
		m_PhyPtr = NULL;
		m_PhySize = 0;
	}
}

void CxStaticBuffer::_Tidy()
{
	if(m_PhyPtr!=NULL)
	{
		xMemoryFree(m_PhyPtr);
		m_PhyPtr = NULL;
		m_PhySize = 0;
	}
}

void CxStaticBuffer::_Copy( const CxStaticBuffer& _Ref )
{
	_Tidy();
	_Alloc( _Ref.m_PhySize);

	if(m_PhyPtr!=NULL)
	{			
		memcpy(m_PhyPtr, _Ref.m_PhyPtr, m_PhySize);
	}
}











